package scau.mis4.chanyulin.utils;

import scau.mis4.chanyulin.base.GF28;

import java.util.LinkedList;
import java.util.List;

/**
 * Created by cyl on 2017/12/28.
 * GF28工具类
 */
public class GF28Utils {

    /**
     * 将GF28数组转为字节数组
     * @param arr
     * @return
     */
    public static byte[] toBytes(GF28[] arr) {
        byte[] bytes = new byte[arr.length];
        for (int i = 0; i < bytes.length; i++) bytes[i] = arr[i].toByte();
        return bytes;
    }

    /**
     * 两个GF28数相乘
     * @param num1
     * @param num2
     * @return
     */
    public static GF28 multi(GF28 num1, GF28 num2) {
        if (ByteUtils.isEqual(num1.getValues(), GF28.ZERO.getValues()) || BitsUtils.isEqual(num2.getValues(), GF28.ZERO.getValues()))
            return GF28.getZeroInstance();
        if (BitsUtils.isOne(num1.getValues())) return num2;
        if (BitsUtils.isOne(num2.getValues())) return num1;
        byte[] k = new byte[] {0, 0, 0, 0, 1, 1, 0, 1, 1};
        List<byte[]> tempList = new LinkedList<>();
        byte[] last = num2.getValues();
        int topPos = BitsUtils.getTopPos(num1.getValues());
        if (topPos == 8) return new GF28(num2.getValues());
        for (int i = 0; i < topPos; i++) {
            if (last[1] == 0)
                last = movLeftFillByZero(last, 1);
            else if (last[1] == 1)
                last = BitsUtils.xor(k, movLeftFillByZero(last, 1));
            tempList.add(last);
        }
        List<byte[]> xorList = new LinkedList<>();
        for (int j = 0; j < num1.getLength() - 1; j++) if (num1.get(j) == 1) xorList.add(tempList.get(7 - j));
        if (num1.get(num1.getLength() - 1) == 1) xorList.add(num2.getValues());
        byte[] result = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0};
        for (byte[] bits : xorList)
            result = BitsUtils.xor(result, bits);
        return new GF28(result);
    }

    /**
     * 字节数组左移，后面补0
     * @param target
     * @param movCount
     * @return
     */
    private static byte[] movLeftFillByZero(byte[] target, int movCount) {
        movCount = movCount % target.length;
        if (movCount == 0) return target;
        byte[] result = new byte[target.length];
        for (int j = movCount; j < target.length; j++)
            result[j - movCount] = target[j];
        for (int k = 0; k < movCount; k++)
            result[target.length - movCount + k] = 0;
        return result;
    }

    /**
     * 两个GF28数求异或（相加）
     * @param num1
     * @param num2
     * @return
     */
    public static GF28 xor(GF28 num1, GF28 num2) {
        byte[] result = new byte[num1.getLength()];
        for (int i = 0; i < num1.getLength(); i++) {
            byte temp = num1.get(i);
            temp ^= num2.get(i);
            result[i] = temp;
        }
        return new GF28(result);
    }

}
